using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics.Contracts;
using Konst3d.Efficiency.Suite;

namespace Konst3d.Efficiency.Suite.SparsedBinary
{
    internal class MonitorStorage: IMonitorStorage, IDisposable
    {
        #region Constants

        private const string MONITOR_FILE_EXT = ".monitor";
        private const string STATISTIC_FILE_EXT = ".statistic";
        private const string EXCEPTIONS_FILE_EXT = ".exceptions";

        #endregion // Constants

        #region Create/Open/Delete Methods

        /// <summary>
        /// 
        /// </summary>
        /// <param name="path">Path containing file name but not extentsion.</param>
        /// <param name="overwrite">Allow to overwrite storage if already exists, IOexception otherwise.</param>
        /// <returns>MonitorStorage instance.</returns>
        public static MonitorStorage Create(string path, bool overwrite, ICryptographicEngine cryptographicEngine, int id, MonitorType type, string title, string description, DateTime created, bool active)
        {
            LabelsStorage labels = null;
            MonitorFile monitorFile = null;
            StatisticStorage statistic = null;
            ActiveDaysStorage activeDays = null;

            try
            {
                labels = LabelsStorage.Create(path, overwrite, cryptographicEngine);

                int titleID = labels.AddLabel(title);
                int descrID = labels.AddLabel(description);

                monitorFile = MonitorFile.Create(path + MONITOR_FILE_EXT, overwrite, id, type, titleID, descrID, created, active ? (byte)1 : (byte)0);
                activeDays  = ActiveDaysStorage.Create(path + EXCEPTIONS_FILE_EXT, overwrite);
                statistic   = StatisticStorage.Create(path + STATISTIC_FILE_EXT, overwrite, labels, activeDays);

                return new MonitorStorage(labels, monitorFile, statistic, activeDays);
            }
            catch
            {
                if (labels != null)
                {
                    labels.Delete();
                }

                if (monitorFile != null)
                {
                    monitorFile.Delete();
                }

                if (statistic != null)
                {
                    statistic.Delete();
                }

                if (activeDays != null)
                {
                    activeDays.Delete();
                }

                throw;
            }
        }

        public static MonitorStorage Open(string path, ICryptographicEngine cryptographicEngine)
        {
            LabelsStorage labels = null;
            MonitorFile monitorFile = null;
            StatisticStorage statistic = null;
            ActiveDaysStorage activeDays = null;

            try
            {
                labels = LabelsStorage.Open(path, cryptographicEngine);
                monitorFile = MonitorFile.Open(path + MONITOR_FILE_EXT);
                activeDays  = ActiveDaysStorage.Open(path + EXCEPTIONS_FILE_EXT);
                statistic   = StatisticStorage.Open(path + STATISTIC_FILE_EXT, labels, activeDays);

                return new MonitorStorage(labels, monitorFile, statistic, activeDays);
            }
            catch
            {
                if (labels != null)
                {
                    labels.Delete();
                }

                if (monitorFile != null)
                {
                    monitorFile.Delete();
                }

                if (statistic != null)
                {
                    statistic.Delete();
                }

                if (activeDays != null)
                {
                    activeDays.Delete();
                }

                throw;
            }
        }

        public void Delete()
        {
            Contract.Assert(!_disposed);

            if (_labels != null)
            {
                _labels.Delete();
            }

            if (_monitorFile != null)
            {
                _monitorFile.Delete();
            }

            if (_statistic != null)
            {
                _statistic.Delete();
            }

            if (_activeDays != null)
            {
                _activeDays.Delete();
            }

            Dispose(true);
        }

        #endregion // Create/Open/Delete Methods

        #region Constructors/Finalizer

        private MonitorStorage(LabelsStorage labels, MonitorFile monitorFile, StatisticStorage statistic, ActiveDaysStorage exceptions)
        {
            Contract.Requires(labels        != null);
            Contract.Requires(monitorFile   != null);
            Contract.Requires(statistic     != null);
            Contract.Requires(exceptions    != null);

            _labels         = labels;
            _monitorFile    = monitorFile;
            _statistic      = statistic;
            _activeDays     = exceptions;

            _name = _labels.GetLabel(_monitorFile.NameID);
            _description = _labels.GetLabel(_monitorFile.DescriptionID);
        }

        ~MonitorStorage()
        {
            Dispose(false);
        }

        #endregion // Constructors/Finalizer

        #region IMonitorStorage Members

        public string Name
        {
            get
            {
                return _name;
            }

            set
            {
                if (!String.IsNullOrEmpty(value))
                {
                    if (_monitorFile.NameID >= 0)
                    {
                        _monitorFile.NameID = _labels.UpdateLabel(_monitorFile.NameID, value);
                    }
                    else
                    {
                        _monitorFile.NameID = _labels.AddLabel(value);
                    }
                }
                else
                {
                    if (_monitorFile.NameID >= 0)
                    {
                        _labels.DeleteLabel(_monitorFile.NameID);
                    }

                    _monitorFile.NameID = -1;
                }

                _name = value;
            }
        }

        public string Description
        {
            get
            {
                return _description;
            }

            set
            {
                if (!String.IsNullOrEmpty(value))
                {
                    if (_monitorFile.DescriptionID >= 0)
                    {
                        _monitorFile.DescriptionID = _labels.UpdateLabel(_monitorFile.DescriptionID, value);
                    }
                    else
                    {
                        _monitorFile.DescriptionID = _labels.AddLabel(value);
                    }
                }
                else
                {
                    if (_monitorFile.DescriptionID >= 0)
                    {
                        _labels.DeleteLabel(_monitorFile.DescriptionID);
                    }

                    _monitorFile.DescriptionID = -1;
                }

                _description = value;
            }
        }

        public MonitorType Type
        {
            get
            {
                return _monitorFile.Type;
            }

            set
            {
                _monitorFile.Type = value;
            }
        }

        public int ID
        {
            get
            {
                return _monitorFile.MonitorID;
            }

            set
            {
                _monitorFile.MonitorID = value;
            }
        }

        public bool Active
        {
            get
            {
                return _monitorFile.Active != 0;
            }

            set
            {
                _monitorFile.Active = value ? (byte)1 : (byte)0;
            }
        }

        public DateTime CreateDate
        {
            get
            {
                return _monitorFile.Created;
            }
        }

        public IActiveDaysStorage ActiveDays
        {
            get
            {
                return _activeDays;
            }
        }

        public IStatisticStorage Statistic
        {
            get
            {
                return _statistic;
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            GC.SuppressFinalize(this);
            Dispose(true);
        }

        private void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _activeDays.Dispose();
                    _statistic.Dispose();
                    _monitorFile.Dispose();
                    _labels.Dispose();
                }

                _disposed = true;
            }
        }

        #endregion

        #region Fields

        private bool _disposed = false;
        private LabelsStorage _labels = null;
        private MonitorFile _monitorFile;
        private StatisticStorage _statistic;
        private ActiveDaysStorage _activeDays;
        private string _name;
        private string _description;

        #endregion // Fields
    }
}
